/*
** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/

#ifndef lparser_h
#define lparser_h

#include "llimits.h"
#include "lobject.h"
#include "lzio.h"


/*
** 表达式和变量描述符。
** 为了允许优化，变量和表达式的代码生成可以被延迟；一个 'expdesc' 结构描述了一个可能被延迟的
** 变量/表达式。它包含了其“主要”值的描述，加上一个条件跳转列表，这些跳转也可以生成其值（由
** 短路运算符 'and'/'or' 生成）。
*/
/**
 *这段话是关于编程中的一个概念，特别是在编译器设计或解释器实现中的一个特定结构的描述。
 * 这个结构被称为 expdesc，它用于描述变量或表达式。这里的关键点如下：
 * 1. 延迟代码生成：通常，在编译或解释代码时，每个变量或表达式都会立即生成相应的机器码或中间代码。
 *    然而，为了进行优化，比如减少生成的代码量或提高执行效率，有时会延迟这个代码生成的过程。
 *    这意味着编译器或解释器会等待，直到有更多的信息可用，或者直到确定了最优的生成方式。
 * 2. expdesc 结构：这是一个数据结构，用于描述一个可能被延迟处理的变量或表达式。这个结构包含了两个主要部分：
      · 主要值的描述：这是变量或表达式的直接值的描述，即在没有任何条件跳转发生时，它应该产生的值。
      · 条件跳转列表：这个列表包含了一系列的条件跳转指令，这些指令是由于使用了短路运算符 and 或 or 而生成的。
        在逻辑运算中，短路运算符允许表达式的评估提前结束，如果已经可以确定整个表达式的结果。
        例如，在表达式 A and B 中，如果 A 为假，则无需评估 B，因为整个表达式的结果已经确定为假。
        这种优化可以减少不必要的计算。
   综上所述，这段话描述的是一个用于编译器或解释器中的结构，该结构用于跟踪和管理变量和表达式的代码生成，特别是在涉及优化和延迟处理时。
 *
*/
/*
** Expression and variable descriptor.
** Code generation for variables and expressions can be delayed to allow
** optimizations; An 'expdesc' structure describes a potentially-delayed
** variable/expression. It has a description of its "main" value plus a
** list of conditional jumps that can also produce its value (generated
** by short-circuit operators 'and'/'or').
*/

/* kinds of variables/expressions
 * 这段代码定义了一个枚举类型expkind，它用于在Lua虚拟机中表示不同种类的变量和表达式。每个枚举值代表了表达式描述符expdesc可以具有的不同状态。
 * */
typedef enum {
    VVOID,  /* when 'expdesc' describes the last expression a list,
             this kind means an empty list (so, no expression)
             'expdesc' 描述列表中的最后一个表达式时，这个种类意味着一个空列表（即，没有表达式）*/
    VNIL,  /* constant nil 常量 nil */
    VTRUE,  /* constant true 常量 true */
    VFALSE,  /* constant false 常量 false*/
    VK,  /* constant in 'k'; info = index of constant in 'k' 常量在 'k' 中；info = 常量在 'k' 中的索引 */
    VKFLT,  /* floating constant; nval = numerical float value 浮点常量；nval = 数值浮点值 */
    VKINT,  /* integer constant; nval = numerical integer value 型常量；nval = 数值整数值 */
    VNONRELOC,  /* expression has its value in a fixed register;
                 info = result register
                 表达式的值在一个固定的寄存器中；
                  info = 结果寄存器 */
    VLOCAL,  /* local variable; info = local register 局部变量；info = 局部寄存器 */
    VUPVAL,  /* upvalue variable; info = index of upvalue in 'upvalues' 上值变量；info = 'upvalues' 中上值的索引 */
    VINDEXED,  /* indexed variable;
                ind.vt = whether 't' is register or upvalue;
                ind.t = table register or upvalue;
                ind.idx = key's R/K index
                索引变量；
                 ind.vt = 't' 是寄存器还是上值；
                 ind.t = 表的寄存器或上值；
                 ind.idx = 键的 R/K 索引
                */
    VJMP,  /* expression is a test/comparison;
            info = pc of corresponding jump instruction
            表达式是一个测试/比较；
            info = 对应跳转指令的 pc
            */
    VRELOCABLE,  /* expression can put result in any register;
                  info = instruction pc
                  表达式可以将结果放在任何寄存器中；
                  info = 指令 pc*/
    VCALL,  /* expression is a function call; info = instruction pc 表达式是一个函数调用；info = 指令 pc */
    VVARARG  /* vararg expression; info = instruction pc 可变参数表达式；info = 指令 pc */
} expkind;

///* 变量/表达式的种类 */
//typedef enum {
//    VVOID,  /* 当 'expdesc' 描述一个列表的最后一个表达式时，
//             这个类型意味着一个空列表（所以，没有表达式） */
//    VNIL,  /* 常量 nil */
//    VTRUE,  /* 常量 true */
//    VFALSE,  /* 常量 false */
//    VK,  /* 'k' 中的常量；info = 常量在 'k' 中的索引 */
//    VKFLT,  /* 浮点常量；nval = 数值型浮点值 */
//    VKINT,  /* 整数常量；nval = 数值型整数值 */
//    VNONRELOC,  /* 表达式的值在一个固定寄存器中；
//                 info = 结果寄存器 */
//    VLOCAL,  /* 局部变量；info = 局部寄存器 */
//    VUPVAL,  /* upvalue 变量；info = upvalue 在 'upvalues' 中的索引 */
//    VINDEXED,  /* 索引变量；
//                ind.vt = 't' 是寄存器还是 upvalue；
//                ind.t = 表寄存器或 upvalue；
//                ind.idx = 键的 R/K 索引 */
//    VJMP,  /* 表达式是一个测试/比较；
//            info = 对应跳转指令的 pc */
//    VRELOCABLE,  /* 表达式可以将结果放在任何寄存器；
//                  info = 指令 pc */
//    VCALL,  /* 表达式是一个函数调用；info = 指令 pc */
//    VVARARG  /* vararg 表达式；info = 指令 pc */
//} expkind;


#define vkisvar(k)  (VLOCAL <= (k) && (k) <= VINDEXED)
#define vkisinreg(k)  ((k) == VNONRELOC || (k) == VLOCAL)

// 它在 Lua 编译器的实现中用于描述表达式的不同方面。
// expdesc 结构体包含了表达式的类型、可能的值以及与表达式相关的一些额外信息。
/**
 * expkind k;：这是一个枚举类型，表示表达式的种类。expkind 可能定义了不同的表达式类型，如变量、常量、跳转等。
 * union { ... } u;：这是一个联合体，它允许 u 成员根据表达式的类型 k 存储不同的数据类型。
 *   lua_Integer ival;：当表达式是一个整数常量（可能由 expkind 中的 VKINT 表示）时，ival 被用来存储整数值。
 *   lua_Number nval;：当表达式是一个浮点数常量（可能由 expkind 中的 VKFLT 表示）时，nval 被用来存储浮点数值。
 *   int info;：一个通用的整数字段，用于存储表达式的其他信息或标志。
 *   struct { ... } ind;：当表达式涉及索引操作（如访问表中的元素，可能由 expkind 中的 VINDEXED 表示）时，
 *   这个匿名结构体被用来存储索引信息。
 *     short idx;：表示索引值，可能用于访问寄存器或上值数组中的元素。
 *     lu_byte t;：表示索引的表，可以是一个寄存器索引或指向一个上值。
 *     lu_byte vt;：指示 t 是指向一个局部变量（VLOCAL）还是一个上值（VUPVAL）。
 * int t;：表示当表达式为真时应该跳转到的代码位置的补丁列表。
 *   这通常用于条件语句和循环语句，其中需要根据表达式的真值来决定程序的流程。
 * int f;：表示当表达式为假时应该跳转到的代码位置的补丁列表。与 t 类似，f 用于控制程序流程，特别是在处理条件分支时。
 */
typedef struct expdesc {
    expkind k;
    union {
        lua_Integer ival;    /* for VKINT */
        lua_Number nval;  /* for VKFLT */
        int info;  /* for generic use */
        struct {  /* for indexed variables (VINDEXED) */
            short idx;  /* index (R/K) */
            lu_byte t;  /* table (register or upvalue) */
            lu_byte vt;  /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
        } ind;
    } u;
    int t;  /* patch list of 'exit when true' */
    int f;  /* patch list of 'exit when false' */
} expdesc;


/* description of active local variable */
typedef struct Vardesc {
    short idx;  /* variable index in stack */
} Vardesc;


/* description of pending goto statements and label statements */
typedef struct Labeldesc {
    TString *name;  /* label identifier */
    int pc;  /* position in code */
    int line;  /* line where it appeared */
    lu_byte nactvar;  /* local level where it appears in current block */
} Labeldesc;


/* list of labels or gotos */
typedef struct Labellist {
    Labeldesc *arr;  /* array */
    int n;  /* number of entries in use */
    int size;  /* array size */
} Labellist;


/* dynamic structures used by the parser
 * 它在 Lua 编译器的实现中用于存储动态数据，这些数据通常与当前函数的局部变量、待处理的跳转（goto）语句
 * 以及活动标签有关。结构体 Dyndata 包含三个主要部分：actvar、gt 和 label。
 * 下面是对 Dyndata 结构体中每个字段的解释：
 *   actvar：这是一个匿名结构体，用于管理当前函数中的活动局部变量（即当前在作用域内的局部变量）。
 *     Vardesc *arr;：指向 Vardesc 类型的数组的指针，Vardesc 是一种描述局部变量的辅助结构体。
 *         arr 数组存储了当前函数所有活动局部变量的信息。
 *     int n;：表示 arr 数组中当前的元素数量，即当前有多少个局部变量是活动的。
 *     int size;：表示 arr 数组的总容量，即它可以存储的局部变量的最大数量。
 *   gt：Labellist 类型的成员，用于存储当前函数中所有待处理的跳转（goto）语句的信息。
 *       Labellist 是可能定义了的另一种结构体，用于管理跳转语句的标签。
 *   label：也是 Labellist 类型的成员，用于存储当前函数中所有活动标签的信息。
 *         活动标签是指那些在代码中已经定义，并且可能被跳转语句引用的标签。
 *   这个结构体是 Lua 编译器在编译函数时用来跟踪和处理动态作用域数据的一种工具。
 *   局部变量、跳转语句和标签是程序控制流的重要组成部分，Dyndata 结构体使得编译器能够有效地管理这些元素。
 */
typedef struct Dyndata {
    struct {  /* list of active local variables */
        Vardesc *arr;
        int n;
        int size;
    } actvar;
    Labellist gt;  /* list of pending gotos */
    Labellist label;   /* list of active labels */
} Dyndata;


/* control of blocks */
struct BlockCnt;  /* defined in lparser.c */


/* state needed to generate code for a given function */
typedef struct FuncState {
    Proto *f;  /* current function header */
    struct FuncState *prev;  /* enclosing function */
    struct LexState *ls;  /* lexical state */
    struct BlockCnt *bl;  /* chain of current blocks */
    int pc;  /* next position to code (equivalent to 'ncode') */
    int lasttarget;   /* 'label' of last 'jump label' */
    int jpc;  /* list of pending jumps to 'pc' */
    int nk;  /* number of elements in 'k' 意思是 Proto f 中的数组k(常量)的长度*/
    int np;  /* number of elements in 'p' */
    int firstlocal;  /* index of first local var (in Dyndata array) */
    short nlocvars;  /* number of elements in 'f->locvars' */
    lu_byte nactvar;  /* number of active local variables */
    lu_byte nups;  /* number of upvalues */
    lu_byte freereg;  /* first free register */
} FuncState;
/**
 * nactvar: number of active local variables
 * 在 Lua 的源码中，nactvar 字段（代表活动局部变量的数量）在多个地方被使用，主要是在编译和执行阶段。以下是一些具体的使用场景：
 * 函数编译：当编译器遇到一个新的局部变量声明时，nactvar 会增加，表示活动局部变量的数量增加。当局部变量离开其作用域时，nactvar 会减少。
 * 寄存器分配：编译器在生成字节码时，需要为每个活动局部变量分配一个寄存器。nactvar 用于确定当前需要多少个寄存器。
 * 作用域分析：在词法分析和作用域分析期间，nactvar 帮助编译器跟踪当前作用域内有多少局部变量是可见的。
 * 代码生成：在生成字节码指令时，如 LOADVAR（加载局部变量）、STOREVAR（存储局部变量）等，编译器会根据 nactvar 来确定指向哪个局部变量。
 * 调试器接口：Lua 的调试器接口可能使用 nactvar 来提供当前函数的活动局部变量信息，这有助于调试器展示当前的局部变量及其值。
 * 错误处理：当执行过程中发生错误，如引用了一个未初始化的变量，编译器或运行时系统可能利用 nactvar 来确定哪个局部变量是未初始化的。
 * 垃圾收集优化：虽然 nactvar 主要用于编译阶段，但它间接地影响垃圾收集。例如，如果一个局部变量不再被引用，
 *         并且 nactvar 的值表明它已经不在活动列表中，那么对应的值可能就不再被需要，可以被垃圾收集器回收。
 * 函数调用：在函数调用时，nactvar 有助于确定需要传递多少个局部变量给被调用的函数。
 * 闭包创建：当创建闭包时，nactvar 可以帮助确定多少个局部变量需要捕获为上值。
 */

LUAI_FUNC LClosure *luaY_parser(lua_State *L, ZIO *z, Mbuffer *buff,
                                Dyndata *dyd, const char *name, int firstchar);


#endif
